package edu.pw.p2pclient.data;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;

import android.os.Environment;
import android.util.Log;

public class DownloadNode extends Resource implements Serializable {

	private static final String TAG = "Resource";
	private static final long serialVersionUID = 4596534663310636126L;

	public static final String P2PFOLDER = "/P2PNetwork/";
	public static final int PART_SIZE = 1048576; // size of part in B

	public static final int PAUSED = 0;
	public static final int DOWNLOADING = 1;
	public static final int QUEUED = 2;
	public static final int DONE = 3;
	public static final int CANCELLED = 4;

	private long mSizeDownloaded;
	private int mState;
	private int mTotalParts;
	private ArrayList<Integer> mDownloadedParts;
	private ArrayList<Integer> mMissingParts;

	public DownloadNode(Resource resource) {

		super(resource);
		mParentPath = Environment.getExternalStorageDirectory()
				.getAbsolutePath() + P2PFOLDER;
		mSizeDownloaded = 0;
		mState = QUEUED;
		mTotalParts = (int) Math.ceil(getLongSize() / (double) PART_SIZE);
		mDownloadedParts = new ArrayList<Integer>();
		mMissingParts = new ArrayList<Integer>();
		for (int i = 0; i < mTotalParts; ++i)
			mMissingParts.add(i);
	}

	public long getDownloaded() {

		return mSizeDownloaded;
	}

	public int getReadyPercent() {
		return (int) (mSizeDownloaded * 100 / (double) mSize);
	}

	public void setState(int state) {

		mState = state;
	}

	public int getState() {

		return mState;
	}

	public synchronized void partDownloadStarted(int part) {
		mMissingParts.remove(Integer.valueOf(part));
	}

	public synchronized void partDownloaded(int part, byte[] data) {

		saveData(part, data);
		mDownloadedParts.add(part);
		mSizeDownloaded += data.length;
		if (mDownloadedParts.size() == mTotalParts)
			setState(DONE);
	}

	public synchronized void partFailed(int part) {
		mMissingParts.add(part);
	}

	private synchronized void saveData(int part, byte[] data) {

		File folder = new File(Environment.getExternalStorageDirectory()
				+ P2PFOLDER);
		boolean success = true;
		if (!folder.exists())
			success = folder.mkdir();
		if (success) {
			FileOutputStream fos = null;
			try {
				fos = new FileOutputStream(getFullPath(), true);
				FileChannel ch = fos.getChannel();
				ch.position(part * DownloadNode.PART_SIZE);
				int size = data.length;
				if (part == mTotalParts - 1)
					size = (int) (mSize - (part * PART_SIZE));
				ch.write(ByteBuffer.wrap(data, 0, size));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				Log.e(TAG, "Saving failed.");
				e.printStackTrace();
			} finally {
				if (fos != null)
					try {
						fos.close();
					} catch (IOException ex) {

					}
			}
		} else
			Log.e(TAG, "Saving failed.");
	}

	public synchronized int getAmountOfMissingParts() {
		return mMissingParts.size();
	}

	public ArrayList<Integer> getMissingParts() {
		return mMissingParts;
	}

	public synchronized int getAmountOfDownloaded() {
		return mDownloadedParts.size();
	}

	public boolean isDone() {
		return mState == DONE;
	}

	public boolean isPaused() {
		return mState == PAUSED;
	}

	public boolean isCancelled() {
		return mState == CANCELLED;
	}

	public boolean isQueued() {
		return mState == QUEUED;
	}

	public boolean isDownloading() {
		return mState == DOWNLOADING;
	}

	public int getTotalParts() {
		return mTotalParts;
	}

}
